/* [n_wmiping]
 *********************
 * Things to remember:
 *
 * - detail is threadsafe, use caution, all changes will be seen by all threads; recommend: only use to .get data never .set
 * - global variables are global to all threads, use load & unload to initialize & free up memory
 * - use global isInit to initialize global variables requiring detail to be setup
 * - when using global isInit, the code must be mutex protected so all threads do not run the init, just one
 * - inter-thread coordination can be coordinated via the provided mutex
 */
#include <process.h>
#include <stdio.h>

#define DLL_EXPORT
#include "start.h"
#include "Database.h"
#include "Wmi.h"

#ifdef _WIN32
#ifdef _DEBUG
   #include <crtdbg.h>
   #undef THIS_FILE
   static char THIS_FILE[] = __FILE__;
   #define new       new( _NORMAL_BLOCK, __FILE__, __LINE__)
   #define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
#endif

#include <iostream>
using namespace std;

#ifdef __cplusplus
extern "C" {
#endif	/*__cplusplus*/


// default global variables within dll
ParamManager *supported = NULL;
// module-specific global variables within dll
bool isInit = false;
Database *db = NULL;


// called after the module is loaded, useful to load global variables; Returns supported actions as a ParamManager*
DECLDIR ParamManager* load(void) {
	supported = new ParamManager();
	supported->setOverwrite(false);
	supported->set("action", "wmiping");

	return supported;
}


// called just before the module is unloaded, useful to unload global variables
DECLDIR void unload(void) {
	if(supported) {
		delete supported;
	}
	if(db) {
		delete db;
	}
}


void init(HANDLE mutex, ParamManager &detail) {
	// ensure we only init once
	if(!isInit) {
//		printf("Init db\r\n");
		db = new Database(
					detail.get("db_user"), detail.get("db_pass"),
					detail.get("db_name"),
					detail.get("db_host"), atoi(detail.get("db_port")));

/*		// take action db connection failed
		if(&(db->conn) == NULL) {
			return;
		}
*/
		// re-establish mysql connection if lost
		bool connect = true;
		mysql_options(&(db->conn), MYSQL_OPT_RECONNECT, &connect);

		isInit = true;
	}
}


DECLDIR void start(HANDLE mutex, ParamManager &detail, char *index) {
	MYSQL_RES *rSelect, *rUpdate;
	MYSQL_ROW row;
	char query[DEFAULT_BUFLEN];
	char netbios[DEFAULT_BUFLEN];

	// mutex protected init sequence
	WaitForSingleObject(mutex, INFINITE);	// Request ownership of mutex
	init(mutex, detail);				// Init sequence
	ReleaseMutex(mutex);					// Release mutex for other threads

/*	// take action db connection failed
	if(&(db->conn) == NULL) {
		printf("mysql_real_connect failed\n");
		// free up mysql thread-specific memory
		mysql_thread_end();
		return;
	}
*/

	// Initialize WMI for use with our ping action
	Wmi wmi;
	wmi.initialize();
	wmi.connect();
	wmi.setSecurity();

	// Perform database query and display info
	BIGNUM *tmp = BN_new();	// add 1 to the index
	BN_dec2bn(&tmp, index);
	BN_add_word(tmp, 1);
	char *sindex = BN_bn2dec(tmp);
	BN_free(tmp);
	sprintf(query, "SELECT netbios FROM %s WHERE id = %d", detail.get("db_table"), sindex);	// plus 1 cause blocks start w/ 0, but table starts w/ 1
	OPENSSL_free(sindex);

	// -- Thread-Safe Mysql call --
	// Request ownership of mutex
    WaitForSingleObject(mutex, INFINITE);
	// Make mysql calls which need Mutex protection
	mysql_query((&db->conn), query);
	rSelect = mysql_store_result(&(db->conn));
	// Release the mutex
	ReleaseMutex(mutex);

	if(rSelect) {
		int num_fields = mysql_num_fields(rSelect);
        while((row = mysql_fetch_row(rSelect))) { 
			for(int i = 0; i < num_fields; i++) { 
				sprintf(netbios, "%s", row[i]);

				// Perfom the ToDo action here
//				printf("[ping %s]\n", netbios);
				bool result = wmi.ping(netbios);

				if(result == 1) {
//					printf("db_set: isPing = 1, %s\n", netbios);
				}
				else {
//					printf("db_set: isPing = 0, %s\n", netbios);
				}
//				else {
//					printf("wmi->ping error occured\n");
//				}

//				if( (result == 0) || (result == 1) ) {
					// Perform database query and display info
					sprintf(query, "UPDATE list SET isPing=%d WHERE id = %s", result, index);

					// -- Thread-Safe Mysql call --
					// Request ownership of mutex
					WaitForSingleObject(mutex, INFINITE);
					// Make mysql calls which need Mutex protection
					mysql_query(&(db->conn), query);
					rUpdate = mysql_store_result(&(db->conn));
					// Release the mutex
					ReleaseMutex(mutex);

					// free up the result form the mysql query
					mysql_free_result(rUpdate);
//				}
			}
        }

		// free up the result form the mysql query
        mysql_free_result(rSelect);
	}
	else {
		printf("[Thread::ping] db query failed\n");
	}

	// free up mysql thread-specific memory
	mysql_thread_end();
}


#ifdef __cplusplus
}
#endif	/*__cplusplus */